/**
 * Centro de Informática - UFPE
 * Disc.: Plataformas de Distribuição (IN1118)
 * Exercício 02 - Implementação da camada de interoperabilidade para o uORB.
 * Alunos: Fábio Chicout (fcfmc) / Alysson Barros (abs4)
 */
package br.ufpe.cin.if1118.exerc02bib.transport;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author fabio
 */
public class TCPTransport implements Transport {

    private TCPAddress address;
    private Socket socket;
    private ServerSocket serverSocket;

    /**
     * Method to a server that needs to accept the client requests.
     * @return
     */
    public boolean accept() {
        try {
            serverSocket = new ServerSocket(address.getPort());
            socket = serverSocket.accept();
        } catch (IOException ex) {
            Logger.getLogger(TCPTransport.class.getName()).log(Level.SEVERE, null, ex);
            return false;
        }
        return true;
    }

    /**
     * Method of the client that wants to make a request
     * @return true for ok connection, false for not connected
     */
    public boolean open() {
        try {
            System.out.println("info> " + address);

            /* Corrigir o ip do servidor q não está vindo.
             * sempre vem null;
             */
            socket = new Socket(address.getServerIp(), address.getPort());

        } catch (IOException ex) {
            Logger.getLogger(TCPTransport.class.getName()).log(Level.SEVERE, null, ex);
            return false;
        }
        return true;
    }

    public void send(Buffer buffer) {
        OutputStream outStream = null;
        int bufSize = buffer.getBufferSize();
        byte[] byteBuffer = new byte[bufSize];

        for (int i = 0; i < bufSize; i++) {
            byteBuffer[i] = buffer.getByteData().get(i).byteValue();
        }

        try {
            outStream = socket.getOutputStream();
            outStream.write(byteBuffer);
            outStream.flush();
        } catch (IOException ex) {
            Logger.getLogger(TCPTransport.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    public int receive(Buffer buffer, int bufferSize) {
        InputStream inStream = null;
        int num = 0;
        int left = bufferSize;
        byte[] byteBuffer = new byte[bufferSize];

        try {
            inStream = socket.getInputStream();
            num = inStream.read(byteBuffer);
            while (left > 0) {
                // If the stream got finished
                if (num == -1) {
                    inStream.close();
                    return -1;
                }
                // If the lenght of the stream is 0 and nothing was read;
                if (num == 0) {
                    break;
                }
                for (byte b : byteBuffer) {
                    buffer.add(b);
                }
                left -= num;
            }
        } catch (IOException ex) {
            Logger.getLogger(TCPTransport.class.getName()).log(Level.SEVERE, null, ex);
            return -1;
        }
        return left;
    }

    public void close() {
        try {
            if (socket != null)
                socket.close();
            if (serverSocket != null)
                serverSocket.close();
        } catch (IOException ex) {
            Logger.getLogger(TCPTransport.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public TCPAddress getAddress() {
        return address;
    }

    public void setAddress(TCPAddress address) {
        this.address = address;
    }
}
